""" Successive-Over-Relaxation method enabled to function in a parellel setup """
configurable = True
from common import *

import pylab

default_data = (0, 1)

def setup(data = default_data):
    import wx
    dlg = wx.TextEntryDialog(
        None, 'Input process id p and process count pc :(p, pc)',
        'Configure Process', str(data))
    if dlg.ShowModal() == wx.ID_OK:
        try:
            data = eval(dlg.GetValue())
        except:
            data = dlg.GetValue()
    dlg.Destroy()
    return data

def ParallelSORFunc(topRowIn,problemIn,bottomRowIn,topRowOut,resultOut,bottomRowOut , data = default_data):
    p = data[0]
    pc = data[1]

    # Read problem
    block= problemIn()

    h=len(block)-1
    w=len(block[0])-1

    # Positive points (above 1)are locked to their value.
    # ( An alternative could be to give two problem sizes,
    # one containing the data and one containing the locked points. )
    locked = []
    for y in range(1,h):
        for x in range(1,w):
            if (block[y][x] > 1):
                locked.append((x,y))

    # Delta is not handled correct in a parallel setup,
    # the last process with an acceptable delta will
    # shutdown the other processes. The correct method is to
    # calculate a global delta covering all blocks and to use
    # this to decide whether to shut down.
    epsilon = 0.001*h*w
    delta = epsilon+1.0
    delta2 = delta

    # Set to -1 * process count, to avoid the algorithm stopping prematurely
    stopping= -pc

    stopping_top = stopping
    stopping_bottom = stopping
    swap = p%2
    iteration= 0
    while(stopping < 1):
        iteration+= 1
        delta=0.0

        swap = int(not swap)
        
        for y in range(1,h):
            for x in range(1,w):
                if (not (x,y) in locked):
                    # Switch between red and black dots.
                    if ((x+swap+(y%2))%2 == 0):
                        old=block[y][x]
                        block[y][x]=0.2*(block[y][x]+block[y-1][x]+block[y+1][x]+block[y][x-1]+block[y][x+1])
                        delta+=abs(old-block[y][x])

        delta2 += delta
        if (iteration%2 == 0):
	    if (delta2<epsilon):
                stopping+= 1
            delta2= 0.0

        #Communicate rows
        if (p%2 == 0 and (p+1) != pc): # Even processes and not the last
            bottomRowOut((stopping,block[-2]))
            (stopping_bottom,block[-1]) = bottomRowIn()
            stopping = min(stopping, stopping_bottom)
        elif (p%2 == 1 and p != 0): # Uneven processes and not the first
            (stopping_top,topRow) = topRowIn()
            stopping = min(stopping, stopping_top)
            topRowOut((stopping,block[1]))
            block[0] = topRow

        if (p%2 == 0 and (p != 0)): # Even processes and not the first
            (stopping_top,topRow) = topRowIn()
            stopping = min(stopping, stopping_top)
            topRowOut((stopping,block[1]))
            block[0] = topRow
        elif (p%2 == 1 and (p+1) != pc): # Unevent processes and not the last
            bottomRowOut((stopping,block[-2]))
            (stopping_bottom,block[-1]) = bottomRowIn()
            stopping = min(stopping, stopping_bottom)


    print "iterations:"+str(iteration) , p
    import sys
    sys.stdout.flush()
    resultOut(block)

    if (p == 0):
        poison(topRowIn)
        poison(topRowOut)        
    if (p+1 == pc):
        poison(bottomRowIn)
        poison(bottomRowOut)
        
    poison(problemIn)
    poison(resultOut)
